/*
 * $Id: TcpGate.cc,v 1.8 2007/06/21 10:49:01 baconevi Exp $
 */

#include "Globals.h"
#include "TcpGate.h"
#include "GateProc.h"
#include "Command.h"
#include <xp/bas/MutexLock.hpp>

#ifdef __linux
	#include <linux/unistd.h>
	#include <sys/syscall.h>
	/* for gettid */
#endif

TcpGate::TcpGate (const xp_char_t* name): Gate (name)
{
 	MutexLock lock (&app_env_mutex);
	setMaxConnections (app_env.gateMaxConnections());
}

int TcpGate::start (int flags)
{
	/* TODO: set thread stack size  - around 2MB
	Thread::setStackSize (1024u * 1024u * 2u);
	*/
        return Thread::start (flags);
}

int TcpGate::main ()
{
	XP_LOG1 (&app_log, name(), XP_LOG_INFO, 
		XP_T("configured to listen on %s"),
		(const xp_char_t*)binding_address.numericService());

	int err_code;
	if (TcpServer::start(&err_code) == -1)
	{
		XP_LOG0 (&app_log, name(), XP_LOG_CRITICAL,
			XP_T("failed to start the service"));
		return -1;
	}

	return 0;
}

int TcpGate::stop ()
{
	return TcpServer::stop();
}

int TcpGate::handle_client (TcpSocket* sock, TcpAddress* addr)
{
	xp_char_t new_name[MAX_NAME_LEN+1];

#if defined(_WIN32)
	xp_sprintf (new_name, xp_countof(new_name),
		XP_T("%s/%d"), name(), (int)GetCurrentThreadId());
#elif defined(SYS_gettid)
	xp_sprintf (new_name, xp_countof(new_name),
		XP_T("%s/%d"), name(), (int)syscall(SYS_gettid));
#else
	xp_sprintf (new_name, xp_countof(new_name),
		XP_T("%s/%x"), name(), (unsigned int)pthread_self());
#endif
	
	GateProc proc (new_name, sock, addr, this);

	XP_LOG0 (&app_log, new_name, XP_LOG_DEBUG,
		XP_T("client connection established"));

	SttpCmd cmd;
	while (!isStopRequested() && !proc.isExitRequested()) 
	{
		if (proc.receiveCmd (&cmd) == -1) 
		{
			if (proc.errorCode() == Sttp::ERR_RECEIVE) break;

			xp_char_t buf[100];
			xp_sprintf (
				buf, xp_countof(buf), XP_T("%d"), proc.errorCode());
			const xp_char_t* err = proc.errorStr();
			proc.sendCmd (CMD_ERR, 2, buf, err);
			XP_LOG1 (&app_log, new_name, XP_LOG_INFO,
				XP_T("cmd reception error - %s"), err);
			break;
		}

		/* TODO: encryption
		{
			MutexLock ms (&gRunEnvMutex);
			AppEnv::EncMode encMode = app_env.encMode();
			if (encMode == AppEnv::ENC_ENABLED) proc.setOptEncSend (true);
			else if (encMode == AppEnv::END_DISABLED) proc.setOptEncSend (false);
			else proc.setOptEncSend (proc.optEncReceive());
		}
		*/

		if (proc.processCmd(cmd) == -1) 
		{
			xp_char_t buf[100];
			xp_sprintf (buf, xp_countof(buf),
				XP_T("%d"), proc.errorCode());
			
			const xp_char_t* err = proc.errorStr();
			proc.sendCmd (CMD_ERR, 2, buf, err);
			XP_LOG1 (&app_log, new_name, XP_LOG_INFO,
				XP_T("cmd processing error - %s"), err);
			break;
		}
	}

	XP_LOG0 (&app_log, new_name, XP_LOG_DEBUG,
		XP_T("client connection closed"));

	return 0;
}
